package org.yscz.mqtt;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.yscz.common.ViewConfig;
import org.yscz.controller.PicturesUploadController;
import org.yscz.entity.Testee;
import org.yscz.mapper.TesteeMapper;
import org.yscz.media.MediaService;
import org.yscz.webSocket.WebSocket;
import org.yscz.common.Constants;
import org.yscz.webSocket.service.impl.WebSocketServiceImpl;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author achen
 * @create 2021-08-19 13:37
 */
@Slf4j
public class PubCallBack implements MqttCallback {

    public static JSONObject jObj;

    private MqttCustomClient client;

    /**
     * 人脸识别是否成功
     */
    public static JSONObject faceRecognitionResultMsg;

    /**
     * 拍照质量评估
     */
    public static JSONObject imageQualityResultMsg;

    public PubCallBack(MqttCustomClient client) throws MqttException {
        this.client = client;
    }

    @Override
    public void connectionLost(Throwable throwable) {
        // 连接丢失后，一般在这里面进行重连
        while (true) {
            try {
                try {
                    TimeUnit.MILLISECONDS.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                client.init();
                break;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 接受算法的消息
     *
     * @param topic
     * @param message
     * @throws Exception
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        // subscribe后得到的消息会执行到这里面
        String result = new String(message.getPayload(), "UTF-8");
        log.info("接收消息主题:[{}]", topic);
        log.info("接收消息Qos:[{}]", message.getQos());
        log.info("接收消息内容:[{}]", result);

        //这里可以针对收到的消息做处理
        if (Constants.FACE_RECOGNITION_RESULT_TOPIC.equals(topic)) {
            this.faceRecognitionResultMsgMethod(result);
        }

        //接受算法信息 进行图片质量评估
        if (Constants.IMAGE_QUALITY_RESULT_TOPIC.equals(topic)) {
            this.imageQualityResultResultMsgMethod(result);
        }
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        //System.out.println("deliveryComplete---------" + iMqttDeliveryToken.isComplete());
    }

    /**
     * 处理人脸识别结果
     */
    private void faceRecognitionResultMsgMethod(String result) {
        //订阅算法信息
        faceRecognitionResultMsg = JSONObject.parseObject(result);

        //如果这个信息不为空，说明识别成功，通过websocket推送给前台
        JSONObject jsonObject = new JSONObject();
        if (!StringUtils.isEmpty(faceRecognitionResultMsg)) {
            //uuid
            String uid = (String) faceRecognitionResultMsg.get(Constants.UUID);
            //是否识别成功返回信息
            String msg = (String) faceRecognitionResultMsg.get(Constants.IS_SUCCESS_MESSAGE);
            //是否存在人脸
            Boolean faceState = (Boolean) faceRecognitionResultMsg.get(Constants.FACE_STATE);
            //时间戳
            Long timestamp = (Long) faceRecognitionResultMsg.get(Constants.TIME_STAMP);

            log.info("算法回调studentid:[{}]", msg);
            Testee testee = GetMediaService.getMediaService.selectTesteeByImageUrl(msg);
            log.info("faceRecognitionResultMsgMethod:[{}]", testee);

            //添加到jsonObject 返给前台
            jsonObject.put("uid", uid);
            jsonObject.put("faceState", faceState);
            jsonObject.put("studentId", msg);
            if (null != testee) {
                jsonObject.put("testeeId", testee.getTesteeId());
            } else {
                jsonObject.put("testeeId", "");
            }
            log.info("匹配不到该人:[{}]", ("".equals(msg) && faceState)); //true

            //通过websocket推给前台信息"人脸库中匹配不到该人"
            if (("".equals(msg)) && faceState) {
                //接收到的算法信息吐过为空字符串表示人脸库中匹配不到该人
                jsonObject.put("msg", "人脸库中匹配不到该人");
                log.info("人脸库中匹配不到该人");
                GetMediaService.getMediaService.delStream(ViewConfig.mediaStartCacheUuid);
            }

            //推给前台信息"视频流中没有人脸"
            if (!faceState) {
                //接收到的算法信息吐过为空字符串表示人脸库中匹配不到该人
                jsonObject.put("msg", "视频流中没有人脸");
                //GetMediaService.getMediaService.delStream(ViewConfig.mediaStartCacheUuid);
                log.info("视频流中没有人脸");
            }

            //推给前台信息"识别成功"
            if (!("".equals(msg)) && faceState) {
                //如果识别成功或者该人已经存在，关闭流媒体
                jsonObject.put("msg", "识别成功");
                //根据msg查询出被测人id

                GetMediaService.getMediaService.delStream(ViewConfig.mediaStartCacheUuid);
                log.info("流媒体关闭，uuid为:[{}]", PicturesUploadController.mediaUuid);
            }

            JSONObject msgObj = new JSONObject();
            msgObj.put("type", "face-recognition-msg");
            msgObj.put("data", jsonObject);

            //拍照质量是否合格
            if (WebSocket.getMainSession() != null) {
                WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(msgObj, SerializerFeature.WriteMapNullValue));
            }
        }
    }

    /**
     * 处理拍照质量评估结果
     *
     * @param result
     */
    private void imageQualityResultResultMsgMethod(String result) {
        log.info("imageResult:[{}]", result);
        //{"uid":"1234","image_url":"c:\desktop","have_face":true,"quality":true,"library_face":true,"face_img_url":"c:\desktop"}
        imageQualityResultMsg = JSONObject.parseObject(result);

        JSONObject jsonObject = new JSONObject();
        if (!StringUtils.isEmpty(imageQualityResultMsg)) {
            //uid
            String uid = (String) imageQualityResultMsg.get(Constants.UUID);
            //image_url
            String imageUrl = (String) imageQualityResultMsg.get(Constants.IMAGE_URL);
            //have_face
            Boolean haveFace = (Boolean) imageQualityResultMsg.get(Constants.HAVE_FACE);
            //quality
            Boolean quality = (Boolean) imageQualityResultMsg.get(Constants.QUALITY);
            //library_have
            Boolean libraryFace = (Boolean) imageQualityResultMsg.get(Constants.LIBRARY_HAVE);
            //裁剪之后的图像路径face_img_url
            String faceImageUrl = (String) imageQualityResultMsg.get(Constants.FACE_IMAGE_URL);

            jsonObject.put("uid", uid);
            jsonObject.put("image_url", imageUrl);
            jsonObject.put("have_face", haveFace);
            jsonObject.put("quality", quality);
            jsonObject.put("library_face", libraryFace);
            jsonObject.put("face_img_url", faceImageUrl);
            jsonObject.put("name", "");

            //进行人脸检测，没有检测到人脸
            if (!haveFace && !quality && !libraryFace) {
                jsonObject.put("msg", "该照片未检测到人脸");
                //jsonObject.put("msg", "拍照失败请重新拍照");
                jsonObject.put("state", false);
            }

            //检测到人脸之后，进行人脸图像清晰度评估，清晰度值未达到阈值
            if (haveFace && !quality && !libraryFace) {
                jsonObject.put("msg", "检测到人脸但人脸清晰度不合格");
                //jsonObject.put("msg", "拍照失败请重新拍照");
                jsonObject.put("state", false);
            }

            //人脸图像清晰度达到阈值时，进行人脸库查重检测，人脸库中未检测到该人
            if (haveFace && quality && !libraryFace) {
                //jsonObject.put("msg","检测成功,可以进行入库操作");
                jsonObject.put("msg", "拍照成功");
                jsonObject.put("state", true);
                log.info("进入拍照成功");

                //关闭流媒体
                GetMediaService.getMediaService.delStream(ViewConfig.mediaStartCacheUuid);
                log.info("拍照成功，流媒体关闭，uuid为:[{}]", ViewConfig.mediaStartCacheUuid);
            }

            if (haveFace && quality && libraryFace) {
                jsonObject.put("msg", "库中已经存在该人信息,不需要新增");
                //jsonObject.put("msg", "该用户已存在");
                jsonObject.put("state", true);

                GetMediaService.getMediaService.delStream(ViewConfig.mediaStartCacheUuid);
                log.info("该用户已存在，流媒体关闭，uuid为:[{}]", ViewConfig.mediaStartCacheUuid);
            }
            //在拍照上传那将这个信息发送给前端
            //jObj = jsonObject;

            Map<String, Object> map = new HashMap<>();
            map.put("type", "image-quality");
            map.put("data", jsonObject);

            //推送给前台人脸识别结果
            if (WebSocket.getMainSession() != null) {
                WebSocket.SendMessage(WebSocket.getMainSession(), JSONObject.toJSONString(map, SerializerFeature.WriteMapNullValue));
            }
        }
    }

    @Component
    public static class GetMediaService {
        @Resource
        private MediaService mediaService;
        @Resource
        private TesteeMapper testeeMapper;
        private static GetMediaService getMediaService;

        @PostConstruct
        public void init() {
            getMediaService = this;
            getMediaService.mediaService = this.mediaService;
            getMediaService.testeeMapper = this.testeeMapper;
        }

        public Testee selectTesteeByImageUrl(String studentId) {
            log.info("静态回调函数studentId:[{}]", studentId);
            QueryWrapper<Testee> queryWrapper = new QueryWrapper<>();
            queryWrapper.like("image_url", studentId);
            List<Testee> testees = testeeMapper.selectList(queryWrapper);
            log.info("静态回调函数testees:[{}]", testees.toString());
            if (!CollectionUtils.isEmpty(testees)) {
                return testees.get(0);
            }
            return null;
        }

        public void delStream(String uuid) {
            mediaService.delSteam(uuid);
            mediaService.stopUsbStream();
        }
    }

    /*public static void main(String[] args) {
        String json = "{\"name\":\"\",\"flag\":true}";
        JSONObject jsonObject = JSONObject.parseObject(json);

        System.out.println(StringUtils.isEmpty(jsonObject.get("name")));
        System.out.println(StringUtils.isEmpty(JSONObject.parseObject(json)));
        System.out.println((Boolean) JSONObject.parseObject(json).get("flag"));
    }*/
}
